# 用于存放用户认证相关的视图函数
import random
from app import redis_cluster
from utils.constants import SMS_CODE_EXPIRE
from flask_restful import Resource

from flask import current_app
from utils.jwt_util import generate_jwt
from datetime import datetime, timedelta
from flask_restful.inputs import regex
from flask_restful.reqparse import RequestParser
from sqlalchemy.orm import load_only
from app import db
from utils.parser import mobile as mobile_type
from models.user import User


# 定义 SMSCodeResource类视图, 实现 get视图函数 用于测试
class SMSCodeResource(Resource):
    """获取短信验证码"""

    # 实现获取验证码视图函数
    def get(self, mobile):
        # 生成短信验证码
        rand_num = '%06d' % random.randint(0, 999999)

        # 保存验证码(redis) app: code:18894578612  123456
        key = 'app:code:{}'.format(mobile)
        redis_cluster.set(key, rand_num, ex=SMS_CODE_EXPIRE)

        # 发送短信  第三方短信平台 celery
        print('短信验证码: "mobile": {}, "code": {}'.format(mobile, rand_num))

        # 返回结果
        return {'mobile': mobile}


# 注册登录类视图
class LoginResource(Resource):
    def post(self):
        """注册登录"""

        # 获取参数
        parser = RequestParser()
        parser.add_argument('mobile', required=True, location='json', type=mobile_type)
        parser.add_argument('code', required=True, location='json', type=regex(r'^\d{6}$'))
        # parse_args 获取到数据对象
        args = parser.parse_args()
        mobile = args.mobile
        code = args.code

        # 校验短信验证码
        key = 'app:code:{}'.format(mobile)
        real_code = redis_cluster.get(key)

        if not real_code or real_code != code:  # 验证失败
            return {'message': 'Invalid Code', 'data': None}, 400

        # 删除验证码
        redis_cluster.delete(key)

        # 校验成功, 查询数据库判断用户是否存在
        # 使用 load_only等语法, 尽量只查询目标字段, 提高查询效率
        user = User.query.options(load_only(User.id)).filter(User.mobile == mobile).first()

        if user:
            # 如果数据库中存在,更新最后登录时间
            user.last_login = datetime.now()
        else:
            # 如果没有,添加用户数据
            user = User(mobile=mobile, name=mobile, last_login=datetime.now())
            db.session.add(user)

        # 无论是更新还是新增都必须提交事务
        db.session.commit()

        # 生成jwt令牌
        token = generate_jwt({'userid': user.id},
                             expiry=datetime.utcnow() + timedelta(days=current_app.config['JWT_EXPIRE_DAYS']))

        # 返回结果
        return {'token': token}, 201
